
#pragma once


#include <Arduino.h>
#include <SoftwareSerial.h>

#include <lipid_count.hpp>
#include <scheduler_basic.hpp>
#include <scheduler_tick.hpp>


// ======================= PIN MAPPING ======================

// 串口TXD
constexpr u8 PIN_TX = 1;
// 串口RXD / I2S_DATA
constexpr u8 PIN_I2S = 3;
// PCF8574 中断输入
constexpr u8 PIN_PCF_INT = 16;
// I2C
constexpr u8 PIN_SDA = 4;
constexpr u8 PIN_SCL = 0;
// 舵机引脚 左前/左后
constexpr u8 PIN_SERVO_LF = 12;
constexpr u8 PIN_SERVO_LR = 2;
// 舵机引脚 右前/右后
constexpr u8 PIN_SERVO_RF = 14;
constexpr u8 PIN_SERVO_RR = 5;
// 串口重映射引脚
constexpr u8 PIN_TX2 = 15;
constexpr u8 PIN_RX2 = 13;

// ======================= PCF8574 ======================

// 两片PCF8574 的地址
constexpr u8 PCF8574_ADDR_1 = 0b0100'000;  // 内部扩展
constexpr u8 PCF8574_ADDR_2 = 0b0100'001;  // 外部扩展

// 内部扩展引脚
// 模拟通道选择，输出
constexpr u8 EX_AS0 = 0;
constexpr u8 EX_AS1 = 1;
constexpr u8 EX_AS2 = 2;
// 滚珠开关，高电平有效，输入
constexpr u8 EX_BALL = 3;
// 音频滤波 / RGB 使能，低电平有效，输出
constexpr u8 EX_LPF_EN = 4;
constexpr u8 EX_RGB_EN = 5;
// 检测DC+ 有没有供电，高电平有效，输入
constexpr u8 EX_DCM = 6;
// 启动升压电路，高电平有效，输出
constexpr u8 EX_BOOST_ON = 7;

/**
 * @brief 输入引脚掩码
 *
 * PCF8574 的输入引脚必须设置为高电平。当外部拉低了输入，单片机读取到低电平，
 * 然后把读到的值写回，这样就会把输入引脚设置为低电平。
 * 所以无论输入引脚当前值是高是低，写回时都要设置为高。
 *
 */
constexpr u8 EX_1_INPUT_MASK = static_cast<u8>(_BV(EX_BALL) | _BV(EX_DCM));


// 外部扩展引脚
constexpr u8 EX_P0 = 0;
constexpr u8 EX_P1 = 1;
constexpr u8 EX_P2 = 2;
constexpr u8 EX_P3 = 3;
constexpr u8 EX_P4 = 4;
constexpr u8 EX_P5 = 5;
constexpr u8 EX_P6 = 6;
constexpr u8 EX_P7 = 7;

constexpr u8 EX_2_INPUT_MASK = 0;  // EX2 暂时不确定，就设置为0


// =================== TIMING ==================


// 时间源
using TimeSource = scheduler_basic::ArduinoMsSource;
using TimeType = typename TimeSource::TimeType;

constexpr u8 TaskCapacity = 16;


// =================== GLOBAL STATIC ==================

extern scheduler_basic::DelayCallback3<TimeSource, TaskCapacity> delay_callback;

using SchedulerType = decltype(delay_callback);
using TaskIndexType = SchedulerType::IndexType;

// 把main.cpp 里的软串口分享给其他模块使用
extern SoftwareSerial serial_log;


// ======================= 电池参数 ======================

constexpr float BATTERY_VOLTAGE_MIN = 3100.0;  // 最低电压，毫伏
constexpr float BATTERY_VOLTAGE_MAX = 4200.0;

// 计算电池电量百分比的函数
constexpr float map_battery_percentage(float voltage) {
    auto v = lipid::value_map<float>(voltage, BATTERY_VOLTAGE_MIN, BATTERY_VOLTAGE_MAX, 0.0, 100.0);
    return lipid::value_constrain<float>(v, 0.0, 100.0);
}


// ======================= WIFI ======================

constexpr const char *AP_SSID = "STUPID_DOG";  // WIFI名称
constexpr const char *AP_PASSWORD = "";


// ======================= 文件 ======================

constexpr const char *APP_PARAM_PATH = "/param.bin";

constexpr const char *HTML_INDEX_PATH = "/index.html";
constexpr const char *HTML_CONTROL_PATH = "/control.html";
constexpr const char *HTML_SETTING_PATH = "/setting.html";